package Methods;

import java.util.Arrays;


import function.Function;
import function.Parser;

public class Secant implements Methods{
	 // output constants
	private static final byte k = 0, a = 1,  fc = 2;
	// input constants
	private static final byte func = 0, pointOne = 1,pointTwo = 2,
			delta = 3,epsilon1=4;

	double[][] result;
	Function function;
	double point1;
	double point2;
	double delt;
    double epsilon;
	public Secant(String f,double p1,double p2) throws Exception{
		this.function = Parser.toFunction(f);
		this.point1 = p1;
		this.point2 = p2;
		this.delt = 1E-9;
		this.epsilon=1E-15;//f(c)
		
		this.result = new double[30][3];
		// Initially fill array with -1
		for (double[] a : result)
			Arrays.fill(a, -1);
		
	}
	
	public Secant(String input[]) throws Exception {

		this.function = Parser.toFunction(input[func]);
		this.point1 = Double.parseDouble(input[pointOne]);
		this.point2 = Double.parseDouble(input[pointTwo]);
		this.delt = Double.parseDouble(input[delta]);
		this.epsilon=Double.parseDouble(input[epsilon1]);
		
		this.result = new double[30][2];
		// Initially fill array with -1
		for (double[] a : result)
			Arrays.fill(a, -1);
	}

	@Override
	public String[] getInputNames() {
		return new String[] { "Function", "Point a","Point b" , "Tolerance","Epsilon" };
	}

	@Override
	public String[] getOutputAddresses() {

		return new String[] {"k", "a","F(c)" };
	}

	@Override
	public String[] getSampleInput() {
		// TODO Auto-generated method stub
		return new String[] { "x*sin(x)-1", "0", "2", ".01" };
	}

	@Override
	public double[][] solve() throws Exception {
		result[0][k]=0;
		result[0][a]=point1;
    	result[0][fc]=function.evaluate(point1);
    	result[1][k]=1;
    	result[1][a]=point2;
    	result[1][fc]=function.evaluate(point2);
		
	   double point3=0;
	   double error=0;
	   double relError=0;
       for(int i = 2 ; i < result.length;i++){
    	result[i][k]=i;
    	result[i][a]=point2-(function.evaluate(point2)*(point2-point1))/(function.evaluate(point2)-function.evaluate(point1));
    	point3=result[i][a];
    	error =Math.abs(point3-point2);
    	relError = 2*error/(Math.abs(point3)+delt);
    	result[i][fc] = function.evaluate(result[i][a]);
    	point1=point2;
    	point2=point3;
    	if(error<delt || relError<delt || Math.abs(function.evaluate(point2))<epsilon)break;
       }
		
		//trim
		int i = 0;
		for(i = 0 ;i<result.length;i++)
		{
			if(result[i][0]==-1)break;
		}
		double [][] trim = Arrays.copyOf(result, i);
		return trim;
	}

	@Override
	public double getError() {
		return 0;
	}

	/**
	 * @param args
	 * @throws Exception
	 */
	public static void main(String[] args) throws Exception {
/*			FalsePosition testFalsePosition = new FalsePosition(new String[] { "x*sin(x)-1",
				"0", "2", ".01","1E-8" });*/
		
		Secant testSecant = new Secant( "((x)^(3))-(0.165*((x)^(2)))+(0.0003993)",0.02,0.05);
		
		double[][] testResult = testSecant.solve();
		
		for (double[] a : testResult)
			System.out.println(Arrays.toString(a));

	}

}